#include <libk/stdio.h>
#include <libk/x86.h>

volatile unsigned short kbflags = 0;

/***************************************************************\
* 			  kbflags				*
*****************************************************************
*	0 - Shift Flag						*
*	1 - Control Flag					*
*	2 - Alt Flag						*
*	3 - Meta Flag						*
*	4 - Caps On						*
*	5 - Num On						*
*	6 - Scroll On						*
*	7 - 							*
*	8 - 							*
*	9 - 							*
*	10 - 							*
*	11 - 							*
*	12 - 							*
*	13 - 							*
*	14 - 							*
*	15 - 							*
\***************************************************************/

unsigned char uskbd[128] =
{
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8',	/* 9 */
  '9', '0', '-', '=', '\b',	/* Backspace */
  '\t',			/* Tab */
  'q', 'w', 'e', 'r',	/* 19 */
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',	/* Enter key */
    0,			/* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',	/* 39 */
 '\'', '`',   0,		/* Left shift */
 '\\', 'z', 'x', 'c', 'v', 'b', 'n',			/* 49 */
  'm', ',', '.', '/',   0,				/* Right shift */
  '*',
    0,	/* Alt */
  ' ',	/* Space bar */
    0,	/* Caps lock */
    0,	/* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,	/* < ... F10 */
    0,	/* 69 - Num lock*/
    0,	/* Scroll Lock */
    0,	/* Home key */
    0,	/* Up Arrow */
    0,	/* Page Up */
  '-',
    0,	/* Left Arrow */
    0,
    0,	/* Right Arrow */
  '+',
    0,	/* 79 - End key*/
    0,	/* Down Arrow */
    0,	/* Page Down */
    0,	/* Insert Key */
    0,	/* Delete Key */
    0,   0,   0,
    0,	/* F11 Key */
    0,	/* F12 Key */
    0,	/* All other keys are undefined */
};

unsigned char us_shift[128] =
{
	0, 27, '!', '@', '#', '$', '%', '^', '&', '*',
	'(', ')', '_', '+', '\b', /* Backspace */
	'\t',	/* Tab */
	'Q', 'W', 'E', 'R',
	'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */
	0,	/* Control */
	'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
	'"', 'Z', 'X', 'C', 'V', 'B', 'N',
	'M', '<', '>', '?', 0, 	/* Right Shift */
	'*',
	0,	/* Alt */
	' ',
	0,	/* CAPS */
	0,	/* F1 key --> */
	0, 0, 0, 0, 0, 0, 0, 0,
	0,	/* <-- F10 key */
	0,	/* Num Lock */
	0,	/* Scroll Lock */
	0,	/* Home Key */
	0,	/* Up Arrow */
	0,	/* Page Up */
	'-',
	0,	/* Left Arrow */
	0,
	0,	/* Right Arrow */
	'+',
	0,	/* End Key */
	0,	/* Down Arrow */
	0,	/* Page Down */
	0,	/* Insert Key */
	0,	/* Delete Key */
	0, 0, 0,
	0,	/* F11 Key */
	0,	/* F12 Key */
	0,	/* All others are undefined */
};

unsigned char us_caps[128] =
{
	0, 27, '1', '2', '3', '4', '5', '6', '7', '8',
	'9', '0', '-', '=', '\b', /* Backspace */
	'\t',	/* Tab */
	'Q', 'W', 'E', 'R',
	'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n', /* Enter key */
	0,	/* Control */
	'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';',
	'\'', 'Z', 'X', 'C', 'V', 'B', 'N',
	'M', ',', '.', '/', 0, 	/* Right Shift */
	'*',
	0,	/* Alt */
	' ',
	0,	/* CAPS */
	0,	/* F1 key --> */
	0, 0, 0, 0, 0, 0, 0, 0,
	0,	/* <-- F10 key */
	0,	/* Num Lock */
	0,	/* Scroll Lock */
	0,	/* Home Key */
	0,	/* Up Arrow */
	0,	/* Page Up */
	'-',
	0,	/* Left Arrow */
	0,
	0,	/* Right Arrow */
	'+',
	0,	/* End Key */
	0,	/* Down Arrow */
	0,	/* Page Down */
	0,	/* Insert Key */
	0,	/* Delete Key */
	0, 0, 0,
	0,	/* F11 Key */
	0,	/* F12 Key */
	0,	/* All others are undefined */
};

void keyboard_handler(void)
{
	unsigned char scancode;

	scancode = inb(0x60);

	if (scancode & 0x80)
	{
		scancode -= 0x80;
		switch (scancode)
		{
			case 29:
				kbflags &= !(1 << 1);
				break;
			case 42:
			case 54:
				kbflags &= !(1 << 0);
				break;
			case 56:
				kbflags &= !(1 << 2);
				break;
		}
	}
	else
	{
		switch (scancode)
		{
			case 29:
				kbflags |= 1 << 1;
				break;
			case 42:
			case 54:
				kbflags |= 1 << 0;
				break;
			case 56:
				kbflags |= 1 << 2;
				break;
			case 58:
				kbflags ^= 1 << 4;
				break;
			//case 59 ... 68:
			//	select_vc(scancode - 59);
				break;
			case 83:
				if ((kbflags &  6) == 6)
					reboot();
				break;

			default:
				if ((kbflags & 1) == 1 && (kbflags & (1 << 4)) == (1 << 4))
				{
					if (us_caps[scancode] == us_shift[scancode])
					{
						putchar(uskbd[scancode]);
					}
					else
					{
						putchar(us_shift[scancode]);
					}
				}
				else if ((kbflags & 1) == 1)
				{
					putchar(us_shift[scancode]);
				}
				else if ((kbflags & (1 << 4)) == (1 << 4))
				{
					putchar(us_caps[scancode]);
				}
				else
				{
					putchar(uskbd[scancode]);
				}
				break;
		}
	}
}

void kb_install()
{
	irq_install_handler(1, (void *)keyboard_handler);
}
